#include "LoadMap.h"
#include "Resource.h"

#include "DynamicBrick.h"
#include "Land.h"
#include "Stair.h"
#include "Heart.h"

#include "Ghost.h"
#include "BatBoss.h"
#include "Dog.h"
#include "RedBat.h"
#include "RedDragon.h"
#include "StoneKnight.h"
#include "HeadDragon.h"
#include "HeadBoss.h"

#include "Items.h"
#include "Brick.h"
#include "Piston.h"

LoadMap::LoadMap(LPDIRECT3DDEVICE9 d3ddv, LPDIRECT3DSURFACE9 backBuffer, LPD3DXSPRITE spriteHandler)
{
	this->d3ddv = d3ddv;
	this->backBuffer = backBuffer;
	this->spriteHandler = spriteHandler;

	numScore = 0;
	numLife = 0;
	numCoin = 0;
	submapToMap = false;

	width_map = 0;
	LoadAllMap("..\\Resources\\Map\\ID_Map.txt");
}


void LoadMap::loadFileObj(string file_name)
{
	string data;
	ifstream fileStream(file_name);
	if (fileStream.is_open())
	{
		while (!fileStream.eof())
		{
			data += fileStream.get();
		}
	}
	vector<string> dataSplit = Utility::split(data, '\n');
	string row_header = dataSplit[0];
	vector<string> element_row = Utility::split(row_header, ' ');

	int width, height;
	width = atoi(element_row[0].c_str());		//lay so cot thong tin obj
	height = atoi(element_row[1].c_str());		//so luong obj
	numScore = atoi(element_row[2].c_str());	//so diem, khi load map
	numLife = atoi(element_row[3].c_str());		//so mang, khi load map
	numCoin = atoi(element_row[4].c_str());		//so coin an dc, khi load map

	posX_first = atoi(element_row[5].c_str());			//vi tri ban dau cua mario
	posY_first = atoi(element_row[6].c_str());
	posX_last = atoi(element_row[7].c_str());			//vi tri sau khi load map, tu map phu sang map chinh tro lai, vi tri cua pipe
	posY_last = atoi(element_row[8].c_str());
	mario_state = atoi(element_row[9].c_str());			//trang thai cua mario
	mario_direction = atoi(element_row[10].c_str());	//kiem tra mario con nho hay k

	for (int i = 1; i <= height; i++)
	{
		string temp = dataSplit[i];
		vector<string> temp_vector = Utility::split(temp, ' ');

		int obj_id = atoi(temp_vector[0].c_str());
		int obj_state = atoi(temp_vector[1].c_str());
		float pos_x =  atoi(temp_vector[2].c_str());
		float pos_y =  atoi(temp_vector[3].c_str());
		int direction = atoi(temp_vector[6].c_str());
		int obj_type = atoi(temp_vector[7].c_str());


		//tao Object
		Object *obj;

		switch (obj_type)
		{
		//case 21:	//heart
		//	obj = new Heart(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
		//	obj->setIDObj(obj_id);
		//	obj_list.push_back(obj);

		//	obj_map[obj_id] = obj;
		//	break;

		case 21:	//Dynamic Brick
			obj = new DynamicBrick(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 22:	//nen dat
			obj = new CLand(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 231:	//stair
			obj = new Stair(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, 1);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 232:	//stair
			obj = new Stair(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, 1);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 233:	//stair
			obj = new Stair(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, 1);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 241:	//stair
			obj = new Stair(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, 2);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 242:	//stair
			obj = new Stair(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, 2);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 243:	//stair
			obj = new Stair(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, 2);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 11:	//ghost
			obj = new Ghost(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, direction);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 121:	//dog left
			obj = new Dog(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, 121, obj_state, 1);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 122:	//dog right
			obj = new Dog(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, 122, obj_state, 2);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 13:	//bat boss
			obj = new BatBoss(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, direction);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 14:	//red bat enemy
			obj = new RedBat(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, direction);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 15:	//red dragon enemy
			obj = new RedDragon(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, direction);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 16:	//stone knight enemy
			obj = new StoneKnight(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, direction);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 17:	//Head Dragon enemy
			obj = new HeadDragon(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, direction);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);
			obj_map[obj_id] = obj;
			break;

		case 18:	//Head Boss enemy
			obj = new HeadBoss(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state, direction);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);
			obj_map[obj_id] = obj;
			break;

//Items --------------------------------------------//
		case 31:	//1 heart - candle
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 32:	//5 heart - candle
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 321:	//5 heart - pot
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 33:	//Whip - pot
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 34:	//Dagger - pot
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 341:	//Dagger - candle
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 35:	//400 pts - candle
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 36:	//700 ptsr - candle
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 37:	//1000 pts - candle
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 38:	//Holy water - candle
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 39:	//Holy cross - candle
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 40:	//Stop watch - candle
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 41:	//Food
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 42:	//Axe - candle
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 43:	//Brick wall
			obj = new Brick(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 431:	//Brick wall - small
			obj = new Brick(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 44:	//Orb - candle
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 45:	//Boomerang - candle
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 46:	//Piston
			obj = new Piston(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;

		case 50:	//check point
			obj = new Items(this->d3ddv, this->backBuffer, this->spriteHandler, pos_x, pos_y, obj_type, obj_state);
			obj->setIDObj(obj_id);
			obj_list.push_back(obj);

			obj_map[obj_id] = obj;
			break;
		

		}

		//them vao obj list
		/*obj_list.push_back(obj);*/
	}

}

void LoadMap::loadFileTiles(string file_name)
{
	string data;
	ifstream fileStream(file_name);
	if (fileStream.is_open())
	{
		while (!fileStream.eof())
		{
			data += fileStream.get();
		}
	}
	vector<string> dataSplit = Utility::split(data, '\n');
	string row_header = dataSplit[0];
	vector<string> element_row = Utility::split(row_header, ' ');

	int width, height;
	width = atoi(element_row[0].c_str());		//lay so cot thong tin tiles obj
	height = atoi(element_row[1].c_str());		//so luong tiles obj
	 
	width_map = atoi(element_row[2].c_str());

	for (int i = 1; i <= height; i++)
	{
		string temp = dataSplit[i];
		vector<string> temp_vector = Utility::split(temp, ' ');

		int obj_id = atoi(temp_vector[0].c_str());		 
		int obj_type = atoi(temp_vector[1].c_str());		 
		int pos_x =  atoi(temp_vector[2].c_str());
		int pos_y =  atoi(temp_vector[3].c_str());

		//tao Tiles Object
		TilesObject *tiles_obj;
		tiles_obj = new TilesObject(obj_id, obj_type, pos_x, pos_y, 32);

		tiles_list.push_back(tiles_obj);

		tiles_map[obj_id] = tiles_obj;

		int x= 0;
	}

}


void LoadMap::loadFileQuadtreeObjToMap(string file_name)
{
	string data;
	ifstream fileStream(file_name);
	if (fileStream.is_open())
	{
		while (!fileStream.eof())
		{
			data += fileStream.get();
		}
	}
	vector<string> dataSplit = Utility::split(data, '\n');

	for (int i = 0; i < dataSplit.size() - 1; i++)
	{
		string temp = dataSplit[i];
		vector<string> temp_vector = Utility::split(temp, ' ');

		int id_node = atoi(temp_vector[0].c_str());
		int pos_x =  atoi(temp_vector[1].c_str());
		int pos_y =  atoi(temp_vector[2].c_str());
		int pos_x2 =  atoi(temp_vector[3].c_str());
		int pos_y2 =  atoi(temp_vector[4].c_str());

		//tao qNode
		QNode *q_obj;
		q_obj = new QNode(pos_x, pos_y, pos_x2 - pos_x, 0, id_node);

		//Dua obj vao list obj cua qNode
		//vector<int> id_obj_vt;
		if (temp_vector.size() >= 5)
		{
			for (int j = 5; j < temp_vector.size(); j++)
			{
				//add cac id object vao node
				int obj_id = atoi(temp_vector[j].c_str());

				q_obj->addGameObject(obj_map[obj_id]);

				/*Object *obj_game;
				list<Object*>::iterator k;
				for (k = this->obj_list.begin(); k != this->obj_list.end(); k++)
				{
					obj_game = *k;
					if (obj_id == obj_game->getIDObj())
					{
						q_obj->addGameObject(obj_game);
					}

				}*/
			}
		}
		

		//them node vao quad tree map
		qTree_map[q_obj->getIDNode()] = q_obj;

	}

	int ii;
}

void LoadMap::loadFileQuadtreeTilesToMap(string file_name)
{
	string data;
	ifstream fileStream(file_name);
	if (fileStream.is_open())
	{
		while (!fileStream.eof())
		{
			data += fileStream.get();
		}
	}
	vector<string> dataSplit = Utility::split(data, '\n');

	for (int i = 0; i < dataSplit.size() - 1; i++)
	{
		string temp = dataSplit[i];
		vector<string> temp_vector = Utility::split(temp, ' ');

		int id_node = atoi(temp_vector[0].c_str());
		int pos_x =  atoi(temp_vector[1].c_str());
		int pos_y =  atoi(temp_vector[2].c_str());
		int pos_x2 =  atoi(temp_vector[3].c_str());
		int pos_y2 =  atoi(temp_vector[4].c_str());

		//tao qNode
		QNode *q_obj;
		q_obj = new QNode(pos_x, pos_y, pos_x2 - pos_x, 0, id_node);

		//Dua obj vao list obj cua qNode
		//vector<int> id_obj_vt;
		if (temp_vector.size() >= 5)
		{
			for (int j = 5; j < temp_vector.size(); j++)
			{
				//add cac id object vao node
				int obj_id = atoi(temp_vector[j].c_str());

				TilesObject* obj_tiles = tiles_map[obj_id];
				q_obj->addTilesBg(obj_tiles);

				/*TilesObject *obj_game;
				list<TilesObject*>::iterator k;
				for (k = this->tiles_list.begin(); k != this->tiles_list.end(); k++)
				{
					obj_game = *k;
					if (obj_id == obj_game->id)
					{
						q_obj->addTilesBg(obj_game);
					}
				}*/
			}
		}


		//them node vao quad tree map
		qTree_map[q_obj->getIDNode()] = q_obj;

	}

	int ii;
}

void LoadMap::deserializeQuadtree(QuadTree *qTree)
{
	QNode *p_qnode = (QNode*) qTree_map[0];

	qTree->setRoot(p_qnode);
	buildQuadtree(qTree->getRoot());
}


void LoadMap::buildQuadtree(QNode *n)
{
	int id_node = n->getIDNode();

	if (!qTree_map[id_node * 10 + 1])
	{
		return;
	}


	if (qTree_map[id_node * 10 + 1])
	{
		n->setLeftTop(qTree_map[id_node * 10 + 1]);
	}

	if (qTree_map[id_node * 10 + 2])
	{
		n->setRightTop(qTree_map[id_node * 10 + 2]);

	}

	if (qTree_map[id_node * 10 + 3])
	{
		n->setLeftBottom(qTree_map[id_node * 10 + 3]);

	}

	if (qTree_map[id_node * 10 + 4])
	{
		n->setRightBottom(qTree_map[id_node * 10 + 4]);

	}


	buildQuadtree(n->getLeftTop());
	buildQuadtree(n->getRightTop());
	buildQuadtree(n->getLeftBottom());
	buildQuadtree(n->getRightBottom());
}

void LoadMap::saveFileObj(char* file_name, list<Object*> obj_list_QT)
{
	//lay obj_list tu quadtree
	//sau do so sanh moi obj trong quadtree voi obj tuong ung trong obj_list cua map
	//cap nhat lai vi tri, trang thai cua obj
	Object *obj_game;
	list<Object*>::iterator i;

	Object *obj_game_QT;
	list<Object*>::iterator j;

	for (i = this->obj_list.begin(); i != this->obj_list.end(); i++)
	{
		obj_game = *i;
		for (j = obj_list_QT.begin(); j != obj_list_QT.end(); j++)
		{
			obj_game_QT = *j;
			if (obj_game->getIDObj() == obj_game_QT->getIDObj())
			{
				//cap nhat vi tri, trang thai obj
				//neu la goomba, koopa, nam mang, nam lon
				switch (obj_game->getIDObjType())
				{
				case 11:
				case 121:
				case 122:
				case 13:
				case 14:
				case 15:
				case 16:
				case 17:
				case 18:
					obj_game->setPosX((int)obj_game_QT->getPosX());
					obj_game->setPosY((int)(obj_game_QT->getPosY() + 1));
					break;

				default:
					obj_game->setPosX(obj_game_QT->getPosX());
					obj_game->setPosY(obj_game_QT->getPosY());
					break;
				}

				/*if (obj_game->getIDObjType() == 11 || obj_game->getIDObjType() == 12 || obj_game->getIDObjType() == 44 ||
					((obj_game->getIDObjType() == 43 || obj_game->getIDObjType() == 45) && obj_game->getObjState() == IS_MOVING))
				{
					obj_game->setPosX((int)obj_game_QT->getPosX());
					obj_game->setPosY((int)(obj_game_QT->getPosY() + 1));
				}
				else
				{
					obj_game->setPosX(obj_game_QT->getPosX());
					obj_game->setPosY(obj_game_QT->getPosY());
				}*/
				obj_game->setObjState(obj_game_QT->getObjState());
			}
		}
	}

	//Ghi thong tin cac obj xuong file
	ofstream fileStream(file_name);
	Object* obj;
	list<Object*>::iterator iList;

	//ghi dong dau tien, so luong obj, so cot thong tin obj, so diem, so mang, so coin an dc, vi tri dau tien, vi tri tiep theo mario, trang thai mario, huong di chuyen
	int width = 8;
	int height = this->obj_list.size();
	fileStream<<width<<" "<<height<<" "<<numScore<<" "<<numLife<<" "<<numCoin<<" "<<posX_first<<" "<<posY_first<<" "<<posX_last<<" "<<posY_last<<" "<<mario_state<<" "<<mario_direction<<"\n";

	for (iList = this->obj_list.begin(); iList != this->obj_list.end(); iList++)
	{
		obj = *iList;
		//id obj, state obj, posx, posy, 0, 0 , huong cua obj, id type obj
		if (obj->getIDObjType() == 46)
			fileStream<<obj->getIDObj()<<" "<<obj->getObjState()<<" "<<obj->getPosXOld()<<" "<<obj->getPosYOld()<<" "<<0<<" "<<0<<" "<<obj->getDirection()<<" "<<obj->getIDObjType()<<"\n";
		else
			fileStream<<obj->getIDObj()<<" "<<obj->getObjState()<<" "<<obj->getPosX()<<" "<<obj->getPosY()<<" "<<0<<" "<<0<<" "<<obj->getDirection()<<" "<<obj->getIDObjType()<<"\n";

	}

	fileStream.close();
}


void LoadMap::LoadAllMap(char* file_name)
{
	string data;
	ifstream fileStream(file_name);
	if (fileStream.is_open())
	{
		while (!fileStream.eof())
		{
			data += fileStream.get();
		}
	}
	vector<string> dataSplit = Utility::split(data, '\n');
	string row_header = dataSplit[0];
	vector<string> element_row = Utility::split(row_header, ' ');	 

	for (int i = 1; i < dataSplit.size(); i++)
	{
		string temp = dataSplit[i];
		vector<string> temp_vector = Utility::split(temp, ' ');

		int key_map = atoi(temp_vector[0].c_str());

		string path_file_obj = temp_vector[1].c_str();
		string path_file_obj_qt = temp_vector[2].c_str();
		string path_file_tile_obj = temp_vector[3].c_str();
		string path_file_tile_obj_qt = temp_vector[4].c_str();

		vector<string> map_vt;
		map_vt.push_back(path_file_obj);
		map_vt.push_back(path_file_obj_qt);
		map_vt.push_back(path_file_tile_obj);
		map_vt.push_back(path_file_tile_obj_qt);

		all_map[key_map] = map_vt;
	}
}

